﻿using System.Text;
using System.Web;
using System.Xml;

namespace Luka;

/// <summary>
/// 字典类型 扩展
/// </summary>
public static class IDictionaryExtension
{
    /// <summary>
    /// 将一个字典转化为 QueryString
    /// </summary>
    /// <param name="urlEncode"></param>
    /// <param name="isToLower">首字母是否小写</param>
    public static string ToQueryString(this IDictionary<string, string> dict, bool urlEncode = true, bool isToLower = false)
    {
        /// <summary>
        /// 字符串首字母小写
        /// </summary>
        static string FirstCharToLower(string str)
        {
            // 空检查
            if (string.IsNullOrWhiteSpace(str))
            {
                return str;
            }
            // 初始化字符串构建器
            var stringBuilder = new StringBuilder(str);
            // 设置字符串构建器首个字符为小写
            stringBuilder[0] = char.ToLower(stringBuilder[0]);
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 将一个字符串 URL 编码
        /// </summary>
        static string UrlEncode(string str)
        {
            return string.IsNullOrEmpty(str) ? "" : HttpUtility.UrlEncode(str, Encoding.UTF8);
        }
        return string.Join("&", dict.Select(p => $"{(urlEncode ? isToLower ? UrlEncode(FirstCharToLower(p.Key)) : UrlEncode(p.Key) : "")}={(urlEncode ? UrlEncode(p.Value) : "")}"));
    }

    /// <summary>
    /// 移除空值项
    /// </summary>
    public static void RemoveEmptyValueItems(this IDictionary<string, string> dict)
    {
        dict.Where(item => string.IsNullOrEmpty(item.Value)).Select(item => item.Key).ToList().ForEach(key =>
        {
            dict.Remove(key);
        });
    }

    /// <summary>
    /// 添加或更新
    /// </summary>
    /// <typeparam name="TKey">字典键类型</typeparam>
    /// <typeparam name="TValue">字典值类型</typeparam>
    public static void AddOrUpdate<TKey, TValue>(this IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value) where TKey : notnull
    {
        // 空检查
        ArgumentNullException.ThrowIfNull(value);

        // 检查键是否存在
        if (!dictionary.TryGetValue(key, out var values))
        {
            values = new();
            dictionary.Add(key, values);
        }

        values.Add(value);
    }

    /// <summary>
    /// 添加或更新
    /// </summary>
    /// <typeparam name="TKey">字典键类型</typeparam>
    /// <typeparam name="TValue">字典值类型</typeparam>
    public static void AddOrUpdate<TKey, TValue>(this IDictionary<TKey, List<TValue>> dictionary, IDictionary<TKey, List<TValue>> concatDictionary) where TKey : notnull
    {
        // 空检查
        ArgumentNullException.ThrowIfNull(concatDictionary);

        // 逐条遍历合并更新
        foreach (var (key, newValues) in concatDictionary)
        {
            // 检查键是否存在
            if (!dictionary.TryGetValue(key, out var values))
            {
                values = new();
                dictionary.Add(key, values);
            }

            values.AddRange(newValues);
        }
    }

    /// <summary>
    /// 添加或更新
    /// </summary>
    /// <typeparam name="TKey">字典键类型</typeparam>
    /// <typeparam name="TValue">字典值类型</typeparam>
    public static void AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, IDictionary<TKey, TValue> concatDictionary) where TKey : notnull
    {
        // 空检查
        ArgumentNullException.ThrowIfNull(concatDictionary);

        // 逐条遍历合并更新
        foreach (var (key, value) in concatDictionary)
        {
            // 检查键是否存在
            if (dictionary.ContainsKey(key))
            {
                dictionary[key] = value;
            }
            else
            {
                dictionary.Add(key, value);
            }
        }
    }

    /// <summary>
    /// 合并两个字典
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static IDictionary<string, T> AddOrUpdate<T>(this IDictionary<string, T> dic, IDictionary<string, T> newDic)
    {
        foreach (var key in newDic.Keys)
        {
            if (dic.TryGetValue(key, out var value))
            {
                dic[key] = value;
            }
            else
            {
                dic.Add(key, newDic[key]);
            }
        }
        return dic;
    }

    /// <summary>
    /// 将Dic字典转换成字符串
    /// </summary>
    public static string DicToXmlStr(this IDictionary<string, object> dic)
    {
        var xml = "<xml>";
        foreach (var (key, value) in dic)
        {
            if (value is int)
                xml += "<" + key + ">" + value + "</" + key + ">";
            else if (value is string)
                xml += "<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">";
        }
        xml += "</xml>";
        return xml;
    }

    /// <summary>
    /// 将字符串转换为Dic字典
    /// </summary>
    public static IDictionary<string, object> XmlStrToDic(this string xml)
    {
        if (string.IsNullOrEmpty(xml))
        {
            throw new Exception("不能转换空字符串！");
        }

        var rltDic = new Dictionary<string, object>();
        var xmlDoc = new XmlDocument { XmlResolver = null };
        xmlDoc.LoadXml(xml);
        var xmlNode = xmlDoc.FirstChild; //获取到根节点<xml>
        if (xmlNode != null)
        {
            var nodes = xmlNode.ChildNodes;
            foreach (XmlNode xn in nodes)
            {
                var xe = (XmlElement)xn;
                rltDic[xe.Name] = xe.InnerText; //获取xml的键值对到WxPayData内部的数据中
            }
        }
        return rltDic;
    }

    /// <summary>
    /// 将Dic字典转换成字符串
    /// </summary>
    public static string SortDicToXmlStr(this SortedDictionary<string, object> dic)
    {
        var xml = "<xml>";
        foreach (var (key, value) in dic)
        {
            if (value is int)
                xml += "<" + key + ">" + value + "</" + key + ">";
            else if (value is string)
                xml += "<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">";
        }
        xml += "</xml>";
        return xml;
    }

    /// <summary>
    /// 将字符串转换为Dic字典
    /// </summary>
    public static SortedDictionary<string, object> XmlStrToSortDic(this string xml)
    {
        if (string.IsNullOrEmpty(xml))
        {
            throw new Exception("不能转换空字符串！");
        }
        var rltDic = new SortedDictionary<string, object>();
        var xmlDoc = new XmlDocument { XmlResolver = null };
        xmlDoc.LoadXml(xml);
        var xmlNode = xmlDoc.FirstChild; //获取到根节点<xml>
        if (xmlNode != null)
        {
            var nodes = xmlNode.ChildNodes;
            foreach (XmlNode xn in nodes)
            {
                var xe = (XmlElement)xn;
                rltDic[xe.Name] = xe.InnerText; //获取xml的键值对到WxPayData内部的数据中
            }
        }
        return rltDic;
    }
}